# ======================================================================
# Copyright TOTAL / CERFACS / LIRMM (03/2020)
# Contributor: Adrien Suau (<adrien.suau@cerfacs.fr>
#                           <adrien.suau@lirmm.fr>)
#
# This software is governed by the CeCILL-B license under French law and
# abiding  by the  rules of  distribution of free software. You can use,
# modify  and/or  redistribute  the  software  under  the  terms  of the
# CeCILL-B license as circulated by CEA, CNRS and INRIA at the following
# URL "http://www.cecill.info".
#
# As a counterpart to the access to  the source code and rights to copy,
# modify and  redistribute granted  by the  license, users  are provided
# only with a limited warranty and  the software's author, the holder of
# the economic rights,  and the  successive licensors  have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using, modifying and/or  developing or reproducing  the
# software by the user in light of its specific status of free software,
# that  may mean  that it  is complicated  to manipulate,  and that also
# therefore  means that  it is reserved for  developers and  experienced
# professionals having in-depth  computer knowledge. Users are therefore
# encouraged  to load and  test  the software's  suitability as  regards
# their  requirements  in  conditions  enabling  the  security  of their
# systems  and/or  data to be  ensured and,  more generally,  to use and
# operate it in the same conditions as regards security.
#
# The fact that you  are presently reading this  means that you have had
# knowledge of the CeCILL-B license and that you accept its terms.
# ======================================================================

import typing as ty

# Definitions used for the gate count.
# _gate_definitions = (
#     ([("X", [0])], [("U3", [0], pi, 0, pi)]),
#     ([("Y", [0])], [("U3", [0], pi, pi / 2, pi / 2)]),
#     ([("Z", [0])], [("U1", [0], pi)]),
#     ([("H", [0])], [("U2", [0], 0, pi)]),
#     ([("S", [0])], [("U1", [0], pi / 2)]),
#     ([("T", [0])], [("U1", [0], pi / 4)]),
#     ([("RX", [0], _theta)], [("U3", [0], _theta, -pi / 2, pi / 2)]),
#     ([("RY", [0], _theta)], [("U3", [0], _theta, 0, 0)]),
#     ([("RZ", [0], _phi)], [("U1", [0], _phi)]),
#     ([("PH", [0], _theta)], [("U1", [0], _theta)]),
#     ([("CNOT", [0, 1])], [("CX", [0, 1])]),
#     (
#         [("C-PH", [0, 1], _lamb)],
#         [
#             ("U1", [0], _div2_var(_lamb)),
#             ("CX", [0, 1]),
#             ("U1", [1], _div2_var(_lamb)),
#             ("CX", [0, 1]),
#             ("U1", [1], _div2_var(_lamb)),
#         ],
#     ),
#     (
#         [("CCNOT", [0, 1, 2])],
#         [
#             ("U2", [2], 0, pi),  # H 2
#             ("CX", [1, 2]),
#             ("U1", [2], -pi / 4),  # T.dag() 2
#             ("CX", [0, 2]),
#             ("U1", [2], pi / 4),  # T 2
#             ("CX", [1, 2]),
#             ("U1", [2], -pi / 4),  # T.dag() 2
#             ("CX", [0, 2]),
#             ("U1", [1], pi / 4),  # T 1
#             ("U1", [2], pi / 4),  # T 2
#             ("U2", [2], 0, pi),  # H 2
#             ("CX", [0, 2]),
#             ("U1", [0], pi / 4),  # T 0
#             ("U1", [1], -pi / 4),  # T.dag() 1
#             ("CX", [0, 1]),
#         ],
#     ),
# )

ibmq_transformation_count = {
    "X": {"U3": 1},
    "Y": {"U3": 1},
    "Z": {"U1": 1},
    "H": {"U2": 1},
    "S": {"U1": 1},
    "T": {"U1": 1},
    "RX": {"U3": 1},
    "RY": {"U3": 1},
    "RZ": {"U1": 1},
    "CNOT": {"CX": 1},
    "C-PH": {"U1": 3, "CX": 2},
    "CCNOT": {"U1": 7, "U2": 2, "CX": 6},
    # A C-C-PH is a controlled-C-PH, so according to the definition of C-PH we have:
    #  - 3 C-U1 which are in facts 3 C-PH, i.e. {"U1": 3*3, "CX": 2*3}
    #  - 2 CCNOT, i.e. {"U1": 7*2, "U2": 2*2, "CX": 6*2}
    # Adding the 2 dicts gives us:
    "C-C-PH": {"U1": 23, "U2": 4, "CX": 18},
    # See https://quantumcomputing.stackexchange.com/q/9444/1386
    "C-H": {"U3": 2, "CX": 1},
}


def gate_count_to_ibmq(gate_count: ty.Dict[str, int]) -> ty.Dict[str, int]:
    returned_gate_count = {"U1": 0, "U2": 0, "U3": 0, "CX": 0}
    for gate_name in gate_count:
        current_gate_ibmq_count = ibmq_transformation_count[gate_name]
        for ibmq_gate_name in returned_gate_count:
            returned_gate_count[ibmq_gate_name] += gate_count[
                gate_name
            ] * current_gate_ibmq_count.get(ibmq_gate_name, 0)
    return returned_gate_count
